﻿/**************************************************************
 *
 * 命名空间：Sgr.UPMS.Infrastructure.Repositories
 * 创建时间：2025/3/20
 * 描述：菜单仓储实现
 *
 **************************************************************/

using Microsoft.EntityFrameworkCore;
using Sgr.Domain.Entities.Auditing;
using Sgr.Domain.Repositories;
using Sgr.Domain.Uow;
using Sgr.EntityFrameworkCore;
using Sgr.Exceptions;
using Sgr.Generator;
using Sgr.UPMS.Domain.Menus;

namespace Sgr.UPMS.Infrastructure.Repositories
{
    /// <summary>
    /// 菜单仓储实现
    /// </summary>
    /// <remarks>
    /// 实现了树形结构的菜单管理，支持：
    /// - 菜单的增删改查
    /// - 菜单层级关系维护
    /// - 同级菜单名称唯一性检查
    /// </remarks>
    public class MenuRepository<TDbContext> :
        EfCoreTreeNodeBaseRepositoryOfTEntityAndTPrimaryKey<TDbContext, Menu, long>, IMenuRepository where TDbContext : UnitOfWorkDbContext
    {
        private readonly ISegmentNumIdGenerator _numberIdGenerator;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContextProvider"></param>
        /// <param name="auditedOperator">审计操作者</param>
        /// <param name="numberIdGenerator">数字ID生成器</param>
        /// <exception cref="BusinessException">参数为空时抛出异常</exception>
        public MenuRepository(
            IDbContextProvider<TDbContext> dbContextProvider,
            IAuditedOperator auditedOperator,
            ISegmentNumIdGenerator numberIdGenerator)
            : base(dbContextProvider, auditedOperator)
        {
            _numberIdGenerator = numberIdGenerator ?? throw new ArgumentNullException(nameof(numberIdGenerator));
        }

        /// <summary>
        /// 检查并设置主键Id
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns></returns>
        protected override async Task CheckAndSetIdAsync(Menu entity, CancellationToken cancellationToken = default)
        {
            if (entity.Id == 0)
                entity.Id = await _numberIdGenerator.GetUniqueIdAsync(UpmsConstant.DEFAULT_SEGMENT_KEY, cancellationToken);
        }

        /// <summary>
        /// 检查同级菜单下是否存在相同名称
        /// </summary>
        /// <param name="name">菜单名称</param>
        /// <param name="parentId">父级菜单ID</param>
        /// <param name="excludeId">需要排除的菜单ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>是否存在</returns>
        public async Task<bool> IsNameExistsInSameLevelAsync(
            string name,
            long parentId,
            long? excludeId = null,
            CancellationToken cancellationToken = default)
        {
            Check.StringNotNullOrEmpty(name, nameof(name));

            var query = await GetQueryableAsync(cancellationToken);
            query = query.AsNoTracking()
               .Where(x => x.ParentId == parentId && x.Name == name);

            if (excludeId.HasValue)
            {
                query = query.Where(x => x.Id != excludeId.Value);
            }

            return await query.AnyAsync(cancellationToken);
        }

        /// <summary>
        /// 检查路由名称是否唯一
        /// </summary>
        /// <param name="routeName">路由名称</param>
        /// <param name="excludeId">需要排除的菜单ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns></returns>
        public async Task<bool> IsRouteNameExistsAsync(string routeName,
            long? excludeId = null,
            CancellationToken cancellationToken = default)
        {
            Check.StringNotNullOrEmpty(routeName, nameof(routeName));

            var query = await GetQueryableAsync(cancellationToken);

            query = query.AsNoTracking()
               .Where(x => x.RouteName == routeName);

            if (excludeId.HasValue)
            {
                query = query.Where(x => x.Id != excludeId.Value);
            }

            return await query.AnyAsync(cancellationToken);
        }
    }
}